﻿#define _CRT_SECURE_NO_WARNINGS 1
//#include <stdio.h>
//
//int main()
//{
//	printf("hello world\n");
//	return 0;
//}

//#include <iostream>
//using namespace std;
//int main()
//{
//	cout << "hello world" << endl;
//	return 0;
//}

//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
////wh是命名空间的名字 - 一般开发中用项目名字做命名空间名。
//namespace wh
//{
//	// 命名空间中可以定义变量/函数/类型
//	int rand = 10;
//	int Add(int left, int right)
//	{
//		return left + right;
//	}
//	struct Node
//	{
//		struct Node* next;
//		int val;
//	};
//}
//void func()
//{
//	printf("%d\n", wh::rand++);
//}
//int main()
//{
//	func();
//	//printf("%p\n", rand);
//	// :: 域作用限定符 - 指定访问wh这个命名空间域里面的东西
//	printf("%d\n", wh::rand);
//	wh::Add(1, 2);
//	struct wh::Node node;
//
//	const char* str = "hello world!";
//	strlen(str);
//
//	return 0;
//}

//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//
//int x = 0;//全局域 - 生命周期是全局的
//
//namespace wh
//{
//	int x = 1;//命名空间域 - 生命周期是全局的
//}
//void func()
//{
//	int x = 2;//局部域 - 生命周期是局部的
//}
//int main()
//{
//	int x = 3;//局部域 - 生命周期是局部的
//
//	//默认访问局部的,先去局部搜索,再去全局搜索
//	//不会到func函数局部域和命名空间域去搜索
//	printf("%d\n", x);
//
//	printf("%d\n", wh::x);//指定命名空间域访问
//
//	printf("%d\n", ::x);//访问全局只添加域作用限定符就行
//
//	//不能访问func局部域的,局部域只能在当前局部域访问
//	return 0;
//}

//#include <stdio.h>
//#include <stdlib.h>
//#include <string.h>
//
//namespace school
//{
//	namespace wh
//	{
//		int rand = 2;
//		int Add(int x, int y)
//		{
//			return x + y;
//		}
//	}
//	namespace cen
//	{
//		int rand = 3;
//		int Add(int x, int y)
//		{
//			return (x + y) * 10;
//		}
//	}
//}
//
//int main()
//{
//	printf("%d\n", school::wh::rand);//指定两层作用域
//	printf("%d\n", school::wh::Add(2,3));
//	printf("%d\n", school::cen::rand);
//	printf("%d\n", school::cen::Add(2,3));
//	return 0;
//}
//#include "Stack.h"
//
// //全局定义了⼀份单独的Stack
//typedef struct Stack
//{
//	int a[10];
//	int top;
//}ST;
//void STInit(ST* ps) {}
//void STPush(ST* ps, int x) {}
//
//int main()
//{
//	//调用全局
//	ST st1;
//	STInit(&st1);
//	STPush(&st1, 1);
//	STPush(&st1, 2);
//	printf("%d\n", sizeof(st1));
//	//调用wh namespace
//	wh::ST st2;//指定命名空间域
//	printf("%d\n", sizeof(st2));
//	wh::STInit(&st2, 4);
//	wh::STPush(&st2,1);
//	wh::STPush(&st2,2);
//	return 0;
//}
//#include <stdio.h>
//namespace wh
//{
//	int a = 0;
//	int b = 1;
//}
//经常用命名空间里面的东西,写起来很麻烦,每次都要指定命名空间
//那么就可以将命名空间的全部成员展开,默认只会在局部找,然后再去
//全局找,有了下面这个东西之后还会去wh命名空间中去找,这样的话编
//译就可以通过,
//using namespace wh;

//如果有命名冲突的话就不能展开命名空间中的全部成员
//int a = 1;

//int main()
//{
//	printf("%d\n", a);
//	return 0;
//}
/*
using namespace wh;这个有的地方被称为展开命名空间,但是这个展开
命名空间跟展开头文件不是一个意思,展开头文件说的是把这个头文件的
内容在预处理的阶段,头文件中实现的各种东西,代码拷贝过来,就没有.h了
展开命名空间本质上是把这个域里面的东西直接暴漏到全局,相当于全局变量
特点就是应用起来比较方便,同时也就有命名冲突的风险,
*/

//#include <stdio.h>
//namespace wh
//{
//	int a = 0;
//	int b = 11;
//}
/*
比如说我这个程序访问a和b,a访问非常的多,b访问不是太多,如果全部展开
b又存在冲突风险的问题,b有冲突风险,a没有冲突风险,其次b用的很少,a用
的很多,所以就有一个在刚才两种方式折中的一种方式,
*/
//不是展开命名空间,而是展开命名空间中的某个变量
//using wh::a;
//
//int b = 2;
//int main()
//{
//	//访问不需要指定
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	printf("%d\n", a);
//	//访问b需要指定 - 访问wh域里面的b
//	wh::b++;
//	printf("%d\n", wh::b);
//	//访问全局域里面的b
//	printf("%d\n", b);
//	return 0;
//}

//#include <iostream>
//
//int main()
//{
//	// <<流插入
//	//自动识别类型,不需要像C语言一样还需要指定格式
//	std::cout << "hello world";
//	int i = 10;
//	std::cout << i;
//	double d = 1.1;
//	std::cout << d;
//
//	//换行
//	//1.如果是字符串,直接在后面加上换行符
//	std::cout << "hello world\n";
//	//2.整型 - 支持连续的输出流插入,甚至类型都可以不一样。
//	int j = 20;
//	std::cout << j << '\n' << "\n";//整型+字符+字符串
//	//3.C++中的换行
//	double k = 1.1;
//	std::cout << k << std::endl;//endl是end line的缩写,是一个函数
//	/*
//	问题:有'\n'这种很简单的换行方式为什么要用endl换行呢?
//	1.在不同的平台下换行符是不一样的,std::endl这种写法可能会很好的
//	兼容,但'\n'这种写法windows平台下可能很好,但是可能换到另外一个平台
//	或者系统的时候可能不一定能很好的支持,
//}
/*
C++中有一些运算符跟C语言进行了一些复用,C语言中<<叫做移位运算符
而C++中<<表示后面的对象流向前面的控制台,cout中的c表示不管什么类型
都要转成字符串,因为在其它设备只有字符串的概念。转的过程其实是内部
自己实现的,std:endl都是会支持的,根据不同平台会进行处理,有些地方可能
还会有一些宽字符等概念,所以std::endl能保证一定换行,而'\n'在不同的
平台不同的编码并不能很好的保证换行。
*/


//#include <iostream>
//
//int main()
//{
//	int i = 10;
//	std::cout << i << std::endl;
//	double d = 1.1;
//	std::cout << d << std::endl;
//
//	//从流里面提取字符 - 转成整型,转成浮点数
//	std::cin >> i >> d;
//	//支持连续的流插入
//	std::cout << i << " " << d << std::endl;
//	//当然scanf和printf也可以使用,C/C++是可以混在一起用的
//	scanf("%d %lf", &i, &d);
//	printf("%d %lf\n", i, d);
//	//输出的时候也会有差异,printf输出的时候会默认保留小数点
//	//后6位,当然也是可以控制的
//	//如果想控制小数点位数或者整型打印宽度的话建议用printf
//	//C++中控制的话会很麻烦
//	printf("%d %.1lf\n", i, d);
//
//	return 0;
//}

//#include <iostream>

//平常练习的时候可以把std展开
//写项目的时候不可以这样,仅限于练习
//using namespace std;

//或者在项目中把cout和endl用的很多,可以考虑单独展开这两个
//using std::cout;
//using std::endl;
//using std::cin;
//
//int main()
//{
//	//流插入
//	/*
//	实际上这些都是函数调用
//	*/
//	cout << "hello world" << endl;
//	int i = 0;
//	//流提取
//	cin >> i;
//
//	cout << i << endl;
//
//	return 0;
//}

/*
C++中cout和cin的效率会低一些,
cout和printf,cin和scanf都是各自的一套输入输出,那么这些都是底层
带缓冲区的,缓冲区就是想输出某些东西,不是直接就到控制台的,是先到
缓冲区的,要遇到一些刷新标准才会出缓冲区,比如说换行,或者就是主动
的刷新接口,刷新之后才会到终端,C++中的cout和C语言中的printf混在一起
使用也不会乱。要进行缓冲区的同步,要进行刷新之前如果缓冲区有东西没有
刷新出去的话会把没有刷新的先刷新出去,所以导致C++中cout等效率会慢一些

如果想要cout和cin变的效率更高一些,可以在mian函数刚开始加上下面代码
ios_base::sync_with_stdio(false)//C++和C语言就不兼容了,把同步关系关掉
cin.tie(nullptr);//不在跟其它的流进行绑定
cout.tie(nullptr);

*/


//#include <iostream>
//int main()
//{
//	//我们没有包含stdio.h这个头文件就可以使用printf和scanf,
//	//stdio.h被间接包含了,所以vs可以编译通过,别的平台下这样写
//	//不行,都要包含,不同的编译器底层的库实现也是有差异的,
//	int u = 0;
//	scanf("%d", &u);
//	printf("%d\n", u);
//	return 0;
//}

//#include <iostream>
//using namespace std;
//void Func(int x = 0)
//{
//	cout << x << endl;
//}
//int main()
//{
//	Func();//没有传参时,使用参数的默认值
//	Func(10);//传参时,使用指定的实参
//	return 0;
//}

//#include <iostream>
//using namespace std;
////全缺省 - 有多个参数,每个参数都给缺省值
//void Func1(int a = 10, int b = 20, int c = 30)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl << endl;
//}
////半缺省 - 缺省部分参数,必须从右边往左缺省
////void Func2(int a = 10, int b, int c = 20) - 不支持
//void Func2(int a, int b = 10, int c = 20)
//{
//	cout << "a = " << a << endl;
//	cout << "b = " << b << endl;
//	cout << "c = " << c << endl << endl;
//}
//int main()
//{
//	Func1();// 可以全不填
//	Func1(1);//可以填一个,就给第一个形参了,后两个缺省
//	Func1(1, 2);//填两个,前两个,最后一个缺省
//	Func1(1, 2, 3);//填三个,与缺省就没有关系了
//	//不能跳跃传 - 不支持
//	//Func1(, 1, );
//
//	Func2(100);//最少得传一个参数。
//	Func2(100, 200);
//	Func2(100, 200, 300);
//
//	return 0;
//}
//#include "Stack.h"
//int main()
//{
//	wh::ST st;
//	//避免了扩容
//	wh::STInit(&st);
//	for (int i = 0; i < 100; i++)
//	{
//		wh::STPush(&st, i);
//	}
//	/*
//	现在这个栈使用顺序结构实现的,我们插入数据的时候
//	它会有一个消耗,这个消耗就是会不断的扩容,扩容是要
//	付出代价的
//	*/
//	return 0;
//}
//#include <iostream>
//using namespace std;
////1.参数类型不同
//int Add(int left, int right)
//{
//	cout << "int Add(int left, int right)" << endl;
//	return left + right;
//}
//double Add(double left, double right)
//{
//	cout << "double Add(double left,double right)" << endl;
//	return left + right;
//}
//int main()
//{
//	Add(10, 20);
//	Add(10.1, 20.2);
//	/*
//	就单独看这两个函数,我们绝对调用的是同一个函数,但实际上调用的是两个
//	函数,一个Add函数是int类型,另一个Add是double类型,用起来就感觉再调
//	同一个函数,但实际是不同的函数,
//	*/
//	return 0;
//}


//#include <iostream>
//using namespace std;
////2.参数个数不同
//void f()
//{
//	cout << "f()" << endl;
//}
//void f(int a)
//{
//	cout << "f(int a)" << endl;
//}
//int main()
//{
//	f();
//	f(1);
//	return 0;
//}

//#include <iostream>
//using namespace std;
////3.参数类型顺序不同(本质还是类型不同)
//void f(int a, char b)
//{
//	cout << "f(int a,char b)" << endl;
//}
//void f(char b, int a)
//{
//	cout << "f(char b,int a)" << endl;
//}
//void Swap(int* x, int* y)
//{
//	//........
//}
//void Swap(double* x, double* y)
//{
//	//........
//}
//int main()
//{
//	f(1,'a');
//	f('b', 1);
//	return 0;
//}

//#include <iostream>
//using namespace std;
////4.返回值不同不能作为重载条件,因为调用的时候也无法区分
//void fx()
//{
//	//....
//}
//int fx()//报错
//{
//	return 0;
//}
//int main()
//{
//	fx();
//	//有返回值可以选择不接收,返回值不同到底调用的是有返回值的还是没
//	//返回值的,完全区分不了,
//	return 0;
//}
//#include <iostream>
//using namespace std;
////下⾯两个函数构成重载
////f()但是调⽤时，会报错，存在歧义，编译器不知道调⽤谁
//void f1()
//{
//	cout << "f()" << endl;
//}
//void f1(int a = -10)
//{
//	cout << "f(int a)" << endl;
//}
//int main()
//{
//	f();
//	f(10);
//	return 0;
//}
//#include <iostream>
//using namespace std;
//int main()
//{
//	int a = 0;
//	//& - 引用,给a这块空间取了一个别名叫做b
//	int& b = a;
//	//给一个变量可以起多个别名
//	int& c = a;
//	//也可以给别名取别名,d相当于还是a的别名
//	int& d = b;
//	++d;
//	//对所有别名取地址我们看到是一样的
//	cout << &a << endl;
//	cout << &b << endl;
//	cout << &c << endl;
//	cout << &d << endl;
//
//	return 0;
//}
/*
注意:&是取别名的,但是typedef也是取别名的,但是&是给变量取别名的,
typedef是给类型取别名的,#define是定义宏的。
*/

//#include <iostream>
//using namespace std;
//
//int main()
//{
//	int a = 2;
//	int* p1 = &a;
//	//给指针变量p1取别名
//	int*& p2 = p1;
//	int b = 10;
//	p2 = &b;
//	cout << *p1 << endl;
//	return 0;
//}

//#include <iostream>
//#include "Stack.h"
//
//using namespace std;
//typedef int STDataType;
//typedef struct Stack
//{
//	STDataType* a;
//	int top; 
//	int capacity;
//}ST;
//void STInit(ST& rs, int n = 4)
//{
//	rs.a = (STDataType*)malloc(n * sizeof(STDataType));
//	rs.top = 0;
//	rs.capacity = n;
//}
//// 栈顶
//void STPush(ST& rs, STDataType x)
//{
//	// 满了，扩容
//		if (rs.top == rs.capacity)
//		{
//			printf("扩容\n");
//			int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;
//			STDataType * tmp = (STDataType*)realloc(rs.a, newcapacity *
//				sizeof(STDataType));
//			if (tmp == NULL)
//			{
//				perror("realloc fail");
//				return;
//			}
//			rs.a = tmp;
//			rs.capacity = newcapacity;
//		}
//	rs.a[rs.top] = x;
//	rs.top++;
//}
//int& STTop(ST& rs)
//{
//	assert(rs.top > 0);
//	return rs.a[rs.top];
//}
//int main()
//{
//	ST st1;
//	STInit(st1);
//	STPush(st1, 1);
//	STPush(st1, 2);
//	return 0;
//}


//typedef struct ListNode
//{
//	int val;
//	struct ListNode* next;
//}LTNode;
//
////要改变LTNode*要用LTNode**
//void ListPushBack(LTNode** pphead, int x);
//
//int main()
//{
//	LTNode* plist;
//	ListPushBack(&plist, 1);
//}

//#include <stdlib.h>
//typedef struct ListNode
//{
//	int val;
//	struct ListNode* next;
//}LTNode, * PNode;
////PNode是结构体指针变量
//void ListPushBack(PNode& phead, int x)
//{
//	PNode newnode = (PNode)malloc(sizeof(LTNode));
//	newnode->val = x;
//	newnode->next = NULL;
//	if (phead == NULL)
//	{
//		phead = newnode;
//	}
//	else
//	{
//	}
//}
//
//int main()
//{
//	PNode plist = NULL;
//	ListPushBack(plist, 1);
//	return 0;
//}

//1.引用在定义时必须初始化
//#include <iostream>
//using namespace std;
//int main()
//{
//	int a = 10;
//	//b是a的别名
//	int& b = a;
//
//	//引用必须初始化
//	int& c;
//	return 0;
//}


//2.一个变量可以有多个引用
//#include <iostream>
//using namespace std;
//int main()
//{
//	int a = 10;
//	//b是a的别名
//	int& b = a;
//	//c也是a的别名
//	int& c = a;
//	//给b取别名,给别名取别名
//	int& d = b;
//	//打印出的地址一样
//	cout << &a << endl;
//	cout << &b << endl;
//	cout << &c << endl;
//	cout << &d << endl;
//
//	return 0;
//}


//3.引用一旦引用一个实体,再不能引用其他实体#include <iostream>
//#include <iostream>
//using namespace std;
//int main()
//{
//	int a = 10;
//	//b是a的别名
//	int& b = a;
//	//c也是a的别名
//	int& c = a;
//	//给b取别名,给别名取别名
//	int& d = b;
//	//创建变量e
//	int e = 20;
//	//这里是赋值 - 可以打印看一下地址
//	//这里并非让d引用e,因为C++引用不能改变指向
//	//这里是一个赋值
//	d = e;
//	cout << &a << endl;
//	cout << &b << endl;
//	cout << &d << endl;
//	cout << &e << endl;
//
//	return 0;
//}
//#include <iostream>
//using namespace std;
//
//int Add(int& x, int& y)
//{
//	return x + y;
//}
//
//int main()
//{
//	int a = 2;
//	int b = 3;
//	int index = Add(a, b);
//	cout << Add(a, b) <<endl;
//	return 0;
//}

//
//#include <iostream>
//using namespace std;
////形参rx,ry是x和y的别名,那么rx和ry的交换其实就是x和y的交换。
////指针也可以达到同样的效果,但是引用用起来更加方便
////改变引用对象时同时改变被引用对象 - 引用对象:rx,ry 被引用对象:x,y
//void Swap(int& rx, int& ry)
//{
//	int tmp = rx;
//	rx = ry;
//	ry = tmp;
//}
//struct A
//{
//	int a[1000];
//};
////减少拷贝,提高效率
////如果该函式是传值调用,那么就把a1拷贝给aa,那么一个a1就有4000个字节,那把4000个字节拷贝
////给aa就是一种消耗。void Func(A aa)
////1.传地址,地址只有4/8个字节,这个时候也能减少拷贝
////2.引用,引用传参会更方便。
//void Func(A& aa)
//{
//	//.....
//}
//int main()
//{
//	
//	int x = 1, y = 2;
//	cout << x << " " << y << endl;
//
//	Swap(x, y);
//	cout << x << " " << y << endl;
//
//	A a1;
//	Func(a1);
//	return 0;
//}

//#include <iostream>
//#include <assert.h>
//using namespace std;
//
//typedef int STDataType;
//typedef struct Stack
//{
//	STDataType* a;
//	int top;
//	int capacity;
//}ST;
////用引用做参数
//void STInit(ST& rs, int n = 4)
//{
//	rs.a = (STDataType*)malloc(n * sizeof(STDataType));
//	rs.top = 0;
//	rs.capacity = n;
//}
//// 栈顶
//void STPush(ST& rs, STDataType x)
//{
//	// 满了，扩容
//
//		if (rs.top == rs.capacity)
//		{
//			printf("扩容\n");
//			int newcapacity = rs.capacity == 0 ? 4 : rs.capacity * 2;
//			STDataType * tmp = (STDataType*)realloc(rs.a, newcapacity *
//				sizeof(STDataType));
//			if (tmp == NULL)
//			{
//				perror("realloc fail");
//				return;
//			}
//			rs.a = tmp;
//			rs.capacity = newcapacity;
//		}
//	rs.a[rs.top] = x;
//	rs.top++;
//}
//// int STTop(ST& rs) - 传值返回
//int* STTop(ST& rs)
//{
//	assert(rs.top > 0);
//	return rs.a+ (rs.top-1);
//}
//int main()
//{
//	//调⽤全局的
//	ST st1;
//	STInit(st1);
//	STPush(st1, 1);
//	STPush(st1, 2);
//	//修改栈顶数据
//	*(STTop(st1))+=1;
//	cout << STTop(st1) << endl;
//	return 0;
//}

//#include <iostream>
//using namespace std;
//int* Func()
//{
//	int ret = 10;
//	ret++;
//	return &ret;
//}
//int main()
//{
//	//越界是不一定报错的
//	int a[10];
//	//越界读不报错
//	cout << a[10] << endl;
//	cout << a[11] << endl;
//	cout << a[12] << endl;
//	cout << a[22] << endl;
//	//越界写不一定报错 - 一般是抽查
//	//a[10] = 1;
//	a[30] = 1;
//
//	return 0;
//}
//#include <iostream>
//using namespace std;
//int main()
//{
	/*const int a = 10;
	const int& b = a;*/

	//const引用也可以引用普通对象.因为对象的
	//访问权限在引用过程中可以缩小
	//int b = 10;
	//const int& rb = b;
	////rb++;
	//b++;

	//const int x = 0;
	//int y = x;

	/*int a = 10;
	int* p1 = &a;
	const int* p2 = p1;*/

//	int b = 20;
//	int* const p1 = &b;
//	int* p2 = p1;
//
//	return 0;
//}


//#include <iostream>
//using namespace std;
//int main()
//{
//	int a = 10;
//	//rb不可以引用,不可以的原因并不是说不能引用这个表达式,
//	//这里引用的就是表达式整体,这个表达式的结果会用临时对象
//	//来存储,C++规定临时对象具有常性,所以这里本质而言也是一种
//	//权限的放大
//	//int& rb = a * 3;
//	//加上const就可以了
//	const int& rb = a * 3;
//
//	double d = 12.34;
//	//d给rd也会产生临时变量,来存储中间的结果,临时对象是int类型
//	//会把浮点数的整数部分截取出来,放到临时对象里面 - 隐式类型转换
//	int rd = d;
//	//这里不行的原因并不是说double不能给int,因为这里引用的不是d,类型
//	//转换中间会产生临时变量,d是先给中间临时对象,临时对象再给rd,也就是
//	//说rd引用的是临时对象,临时对象具有常性,就像被const修饰一样,所以这
//	//里本质是触发了权限的放大
//	//int& rc = d;
//	//所以加上const就可以了
//	const int& rc = d;
//
//}

//#include <iostream>
//using namespace std;
////如果用引用传参不改变形参,就像Swap这个函数本身就得改变形参,如果不改变
////形参的话建议加上const,加上const以后传参就会非常的宽泛
//void f1(int rx)
//{
//	//假设这里有代码
//}
//int main()
//{
//	int a = 10;
//	const int& rb = a * 3;
//	double d = 12.34;
//	const int& rd = d;
//	const int b = 20;
//	//a是可读可写,传给rx,rx变成a的别名,变成const引用,权限被缩小
//	f1(a);
//	f1(a * 3);
//	f1(d); 
//	f1(b);
//	//const引用传参,可以传const对象,也可以传普通对象,权限可以缩小
//	//也可以传表达式,也可也传带类型转换的.const去掉以后很多传参
//	//就传不过去了
//	//const引用const对象,也可以引用普通对象,还可以引用临时对象
//	return 0;
//}
//#include <iostream>
//using namespace std;
//int main()
//{
//	int x = 0;
//	int& rx = x;
//	rx += 1;
//	int* ptr = &x;
//	*ptr += 1;
//	return 0;
//}

//#include <iostream>
//using namespace std;

//错误的宏
//#define ADD(int a, int b) return a + b;
//#define ADD(a, b) a + b;
//#define ADD(a, b) (a + b)
 // 正确的宏实现
//#define ADD(a, b) ((a) + (b))
//为什么不能加分号?
//为什么要加外面的括号?
//为什么要加里面的括号?

//int main()
//{
//	//-----------1.不能加分号------------
//	//多了一个;在这种场景下时没有问题的
//	int ret = ADD(1, 2);//int ret = ((1)+(2));;
//	//这种场景下不可以的,cout << ADD(1, 2); << endl; 提前一个语句结束
//	cout << ADD(1, 2) << endl;
//	//这种情况也是不可以的
//	if(ADD(1,2)){}
//	//----------2.要加外面的括号----------
//	cout << ADD(1, 2)*3 << endl;//如果不加括号就被替换位1+2*3,结果就不对
//	//----------3.要加里面的括号
//	int x = 1, y = 2;
//	ADD(x & y, x | y);// -> (x&y+x|y) -> 加法优先级高,会先算+
//	return 0;
//}
/*
C语言的宏有这么多的缺点,那么为什么还要搞宏出来呢?
宏也是有优势的,宏函数比起写一个Add函数的优势是直接替换,如果是一个普通
函数的话,调用函数是需要建立函数栈帧的,建立栈帧是有开销的,所以宏函数
虽然缺点很多,但是替换机制,调用时不用建立栈帧,提效
*/

//#include <iostream>
//using namespace std;
//inline int Add(int x, int y)
//{
//	int ret = x + y;
//	ret += 1;
//	ret += 1;
//	ret += 1;
//	ret += 1;
//	ret += 1;
//	ret += 1;
//	ret += 1;
//	ret += 1;
//	ret += 1;
//	return ret;
//}
//int main()
//{
//	int index = Add(1, 2);
//	cout << index << endl;
//	return 0;
//}

//#include "Func.h"
//int main()
//{
//	//无法解析的外部符号 "void __cdecl f(int)" (? f@@YAXH@Z)
//	f(10);
//	NULL;
//	return 0;
//}

#include <iostream>
using namespace std;
void f(int x)
{
	cout << "f(int x)" << endl;
}
void f(int* ptr)
{
	cout << "f(int* ptr)" << endl;
}
int main()
{
	f(0);
	// 本想通过f(NULL)调用指针版本的f(int*)函数,但是由于
	//NULL被定义成0,调用了f(intx),因此与程序的初衷相悖。
	f(NULL);

	f((int*)NULL);
	//编译报错:error C2665:"f":2个重载中没有⼀个可以转换所有参数类型
	//f((void*)NULL);

	f(nullptr);
	return 0;
}
